﻿#region System Namespaces
using System.Collections.Generic;
using System.Linq;
#endregion

#region Styx Namespaces

using GiwinMonk.Settings;
using Styx;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
#endregion

namespace GiwinMonk.Helpers
{
    internal static class Unit
    {
        public static HashSet<uint> IgnoreMobs = new HashSet<uint>
            {
                52288, // Venomous Effusion (NPC near the snake boss in ZG. Its the green lines on the ground. We want to ignore them.)
                52302, // Venomous Effusion Stalker (Same as above. A dummy unit)
                52320, // Pool of Acid
                52525, // Bloodvenom

                52387, // Cave in stalker - Kilnara
            };


        public static IEnumerable<WoWPartyMember> GroupMemberInfos
        {
            get
            {
                return StyxWoW.Me.GroupInfo.RaidMembers;
            }
        }

        public static IEnumerable<WoWUnit> NearbyUnfriendlyUnits(int yards)
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(p => ValidUnit(p) && p.DistanceSqr <= yards * yards).ToList();
        }
        public static IEnumerable<WoWUnit> FriendIsDead()
        {
            return ObjectManager.GetObjectsOfType<WoWPlayer>(false, false).Where(o => o != null && o.IsInMyPartyOrRaid && o.IsDead && !StyxWoW.Me.Combat).ToList();
        }
        public static IEnumerable<WoWUnit> HostileIsMyTargetAndApproaching()
        {
            return ObjectManager.GetObjectsOfType<WoWPlayer>(false, false).Where(o => o != null && o.IsHostile && o.Distance < 10 && StyxWoW.Me.Combat && o.IsFacing(StyxWoW.Me) && o.CurrentTarget.IsMe).ToList();
        }
        public static IEnumerable<WoWUnit> TargetsWithinMeleeDistanceAndMeFacingTarget()
        {
            return
                ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                    p =>
                    p != null &&
                    new WoWGroupInfo().IsInParty &&
                    p.IsHostile &&
                    p.IsWithinMeleeRange &&
                                     p.Name != "Skull Banner" &&
                    StyxWoW.Me.CurrentTarget != null &&
                    p.IsPlayer &&
                    p.Location.Distance(StyxWoW.Me.CurrentTarget.Location) < 3.5 &&
                    StyxWoW.Me.IsSafelyFacing(StyxWoW.Me.CurrentTarget));
        }
        public static IEnumerable<WoWPlayer> OtherRangedTargetsTargettingPartyMemberAndCastingHostileSpell()
        {
            return ObjectManager.GetObjectsOfType<WoWPlayer>(false, false).Where(o => o != null && (new WoWGroupInfo().IsInParty &&
                                                                                                    o.IsHostile &&
                                                                                                    o.IsCasting &&
                                                                                                    o.CurrentTarget.IsTargetingMyPartyMember &&
                                                                                                    StyxWoW.Me.PartyMembers[0] != null &&
                                                                                                    StyxWoW.Me.PartyMembers[0].Distance < 30 &&
                                                                                                    o.IsPlayer &&
                                                                                                    o.Name != "Skull Banner" &&
                                                                                                    !o.IsPet &&
                                                                                                    o.Class == WoWClass.Mage ||
                                                                                                    o.Class == WoWClass.Warlock ||
                                                                                                    o.Class == WoWClass.Shaman ||
                                                                                                    o.Class == WoWClass.Priest ||
                                                                                                    o.Class == WoWClass.Druid));
        }
        public static IEnumerable<WoWPlayer> SomeoneIsCastingCrowdControlSpellOnMe()
        {
            return ObjectManager.GetObjectsOfType<WoWPlayer>(false, false).Where(p => p != null &&
                                                                                      new WoWGroupInfo().IsInParty &&
                                                                                      p.IsHostile &&
                                                                                      p.IsPlayer &&
                                                                                      !p.IsPet &&
                                                                                      p.Name != "Skull Banner" &&
                                                                                      p.Distance < 40 &&
                                                                                      p.CurrentTarget.IsMe &&
                                                                                      !p.IsCastingHealingSpell);
        }

        public static List<WoWPlayer> AddsOnMe()
        {
            return ObjectManager.GetObjectsOfType<WoWPlayer>(false, false).Where(p => p != null &&
                                                                                      p.IsHostile &&
                                                                                      p.IsPlayer &&
                                                                                      p.Name != null &&
                                                                                      p.Name != "Skull Banner" &&
                                                                                      p.Distance < 40 &&
                                                                                      StyxWoW.Me.Combat &&
                                                                                      p.CurrentTarget != null &&
                                                                                      p.CurrentTarget.IsMe).ToList();
        }
        public static List<WoWPlayer> TargetNearby()
        {
            return ObjectManager.GetObjectsOfType<WoWPlayer>(false, false).Where(p => p != null &&
                                                                                      new WoWGroupInfo().IsInParty &&
                                                                                      p.IsHostile &&
                                                                                      p.IsPlayer &&
                                                                                      p.Name != "Skull Banner" &&
                                                                                      p.Distance < 10).ToList();
        }

        public static List<WoWPlayer> HavePosion()
        {
            return ObjectManager.GetObjectsOfType<WoWPlayer>(false, false).Where(p => p != null &&
                                                                                      !StyxWoW.Me.IsCasting &&
                                                                                      !StyxWoW.Me.IsChanneling).ToList();
        }



        public static IEnumerable<WoWUnit> DetectTotem()
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                                o => o != null &&
                                     o.IsTotem &&
                                     o.Name != "Skull Banner" &&
                                     o.Name == "Grounding Totem" &&
                                     o.InLineOfSight &&
                                     StyxWoW.Me.CurrentChi >= 1 &&
                                     o.IsHostile).ToList();
        }


        public static List<WoWUnit> Adds
        {
            get
            {
                var ret = from o in ObjectManager.GetObjectsOfType<WoWUnit>(true, false)
                          where
                              o.IsValid &&
                              o.Distance < 15 &&
                              (StyxWoW.Me.CurrentTarget == null || o != StyxWoW.Me.CurrentTarget) &&
                              !o.IsFriendly &&
                              !o.IsTotem &&
                              !o.IsPet &&
                              (o.IsTargetingMeOrPet ||
                               o.IsTargetingMyPartyMember ||
                               o.IsTargetingMyRaidMember
                              )
                          orderby o.DistanceSqr ascending
                          select o;
                return ret.ToList();
            }
        }



        /*
        public static IEnumerable<WoWUnit> ImWhiteTrashandImInTrouble()
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                o => o != null &&
                     o.IsAlive &&
                     new WoWGroupInfo().IsInParty &&
                     StyxWoW.Me.PartyMembers[0] != null &&
                     StyxWoW.Me.PartyMembers[0].IsAlive &&
                     o.CurrentTarget != null &&
                     o.CurrentTarget.IsTargetingMyPartyMember &&
                     StyxWoW.Me.PartyMembers[0].HealthPercent < 50 &&
                     !o.IsWithinMeleeRange &&
                     o.IsHostile).ToList();
        }*/

        public static IEnumerable<WoWUnit> RunnerSpinningFireBlossom()
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                                o => o != null &&
                                     o.HealthPercent < 10 &&
                                     o.InLineOfSight &&
                                     o.IsPlayer &&
                                     o.IsAlive &&
                                     o.Name != "Skull Banner" &&
                                     StyxWoW.Me.CurrentChi >= 1 &&
                                     o.IsHostile).ToList();
        }

        public static IEnumerable<WoWUnit>  FollowerPathOfBlossoms()
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                                o => o != null &&
                                     o.IsBehind(StyxWoW.Me) &&
                                     o.IsAlive &&
                                     o.Name != null &&
                                     o.Name != "Skull Banner" &&
                                     o.IsHostile &&
                                     StyxWoW.Me.IsMoving &&
                                     o.CurrentTarget != null &&
                                     o.CurrentTarget.IsMe).ToList();
        }

        public static IEnumerable<WoWUnit> TealcEyeBrowRaise()
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                                o => o != null &&
                                     o.IsStealthed &&
                                     o.IsHostile).ToList();
        }
        public static IEnumerable<WoWUnit> ParalysisHealingSpell()
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                                o => o != null &&
                                     o.IsHostile &&
                                     o.IsAlive &&
                                     o.Name != "Skull Banner" &&
                                     o.IsPlayer &&
                                     o.IsCastingHealingSpell &&
                                     o.CanInterruptCurrentSpellCast &&
                                     o.Distance <= 20).ToList();
        }
        /*
        public static IEnumerable<WoWUnit> ParalysisSameTarget()
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                                o => o != null &&
                                     StyxWoW.Me.PartyMembers[0] != null &&
                                     StyxWoW.Me.CurrentTarget != null &&
                                     StyxWoW.Me.PartyMembers[0].CurrentTarget != null &&
                                     StyxWoW.Me.PartyMembers[0].CurrentTarget == StyxWoW.Me.CurrentTarget &&
                                     o.IsHostile &&
                                     !o.IsPet &&
                                     o.IsAlive &&
                                     o.Name != null &&
                                     o.Name != "Skull Banner" &&
                                     StyxWoW.Me.CurrentTarget != o.CurrentTarget &&
                                     o.Distance <= 20 &&
                                     o.CurrentTarget.HealthPercent <= MIRsettings.Instance.ParalysisSameTargetHealthPercent).ToList();
        }*/
        public static IEnumerable<WoWUnit> CcOtherTarget()
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                                o => o != null &&
                                     new WoWGroupInfo().IsInParty &&
                                     StyxWoW.Me.CurrentTarget != null &&
                                     StyxWoW.Me.CurrentTarget != o &&
                                     o.IsHostile &&
                                     o.IsAlive &&
                                     o.IsPlayer &&
                                     o.IsWithinMeleeRange &&
                                     !o.IsPet &&
                                     o.Name != "Skull Banner" &&
                                     StyxWoW.Me.CurrentTarget.HealthPercent < 50).ToList();
        }
        public static IEnumerable<WoWPlayer> SwitchToTargetLowHealth()
        {
            return ObjectManager.GetObjectsOfType<WoWPlayer>(false, false).Where(o =>
                                                                                 o != null &&
                                                                                 o.IsPlayer &&
                                                                                 o.IsHostile &&
                                     !o.IsPet &&
                                                                                 o.IsAlive &&
                                     o.Name != "Skull Banner" &&
                                                                                 !o.HasAura("Ice Block") &&
                                                                                 o.HealthPercent <
                                                                                 MIRsettings.Instance.
                                                                                     SwitchPartyTargetHealthPercentBelow &&
                                                                                 StyxWoW.Me.CurrentTarget.HealthPercent >
                                                                                 MIRsettings.Instance.
                                                                                     SwitchMyTargetHealthPercentAbove);
        }


        // Mage Iceblock
        // Paladin Bubble


        public static bool ValidUnit(WoWUnit p)
        {
            if (IgnoreMobs.Contains(p.Entry))
                return false;

            // Ignore shit we can't select/attack
            if (!p.CanSelect || !p.Attackable)
                return false;

            // Ignore friendlies!
            if (!p.IsHostile)
                return false;

            // Duh
            if (p.IsDead)
                return false;

            // If its a pet, lets ignore it please.
            //if (p.IsPet || p.OwnedByRoot != null)
            //    return false;

            // And ignore critters/non-combat pets
            if (p.IsNonCombatPet || p.IsCritter)
                return false;

            return true;
        }

        public static IEnumerable<WoWUnit> UnfriendlyUnitsNearTarget(float distance)
        {
            var dist = distance * distance;
            var curTarLocation = StyxWoW.Me.CurrentTarget.Location;
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                        p => ValidUnit(p) && p.Location.DistanceSqr(curTarLocation) <= dist).ToList();
        }

        /// <summary>
        ///  Check the aura count thats created by yourself by the name on specified unit
        /// </summary>
        /// <param name="aura"> The name of the aura in English. </param>
        /// <param name="unit"> The unit to check auras for. </param>
        /// <returns></returns>
        public static bool HasMyAura(this WoWUnit unit, string aura)
        {
            return HasMyAura(unit, aura, 0);
        }

        public static bool HasMyAura(this WoWUnit unit, string aura, int stacks)
        {
            return HasAura(unit, aura, stacks, StyxWoW.Me);
        }

        private static bool HasAura(this WoWUnit unit, string aura, int stacks, WoWUnit creator)
        {
            return unit.GetAllAuras().Any(a => a.Name == aura &&
                a.StackCount >= stacks &&
                (creator == null || a.CreatorGuid == creator.Guid));
        }

        public static bool HasAnyAura(this WoWUnit unit, params string[] auraNames)
        {
            var auras = unit.GetAllAuras();
            var hashes = new HashSet<string>(auraNames);
            return auras.Any(a => hashes.Contains(a.Name));
        }

        public static bool HasAuraWithMechanic(this WoWUnit unit, params WoWSpellMechanic[] mechanics)
        {
            var auras = unit.GetAllAuras();
            return auras.Any(a => mechanics.Contains(a.Spell.Mechanic));
        }
        //public static List<WoWPlayer> ResurrectablePlayers
        //{
        //    get
        //    {
        //        return (List<WoWPlayer>)ObjectManager.GetObjectsOfType<WoWPlayer>().Where(
        //            p => !p.IsMe && p.IsDead && IsInGroup(StyxWoW.Me) && p.IsFriendly &&
        //                p.IsInMyPartyOrRaid && p.InLineOfSight && p.Distance <= 40 && !p.Combat);
        //    }
        //}
        public static List<WoWPlayer> CanResurrect
        {
            get
            {
                return (List<WoWPlayer>)ObjectManager.GetObjectsOfType<WoWPlayer>().Where(
                    p => !p.IsMe && p.IsDead && IsInGroup(StyxWoW.Me) && p.IsFriendly && p.IsInMyPartyOrRaid && p.InLineOfSight);
            }
        }


        public static bool IsCrowdControlled(this WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return auras.Any(
                a => a.Spell.Mechanic == WoWSpellMechanic.Asleep ||
                    a.Spell.Mechanic == WoWSpellMechanic.Horrified ||
                    a.Spell.Mechanic == WoWSpellMechanic.Fleeing ||
                    a.Spell.Mechanic == WoWSpellMechanic.Charmed ||
                    a.Spell.Mechanic == WoWSpellMechanic.Frozen ||
                    a.Spell.Mechanic == WoWSpellMechanic.Polymorphed ||
                    a.Spell.Mechanic == WoWSpellMechanic.Rooted ||
                    a.Spell.Mechanic == WoWSpellMechanic.Stunned ||
                    a.Spell.Mechanic == WoWSpellMechanic.Disoriented ||
                    a.Spell.Mechanic == WoWSpellMechanic.Incapacitated
                     );
        }

        public static bool IsInGroup(this LocalPlayer me)
        {
            return StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid;
        }
    }
}
